// UE实例管理模块

const fs = require("fs");
const path = require("path");
const UEInstance = require("../../models/ueInstance");
const baseConfig = require("../../../config/config");
const socketClientManager = require("../socketClient");
const pm2 = require("pm2");
const axios = require("axios");
class UEInstanceManager {
  constructor() {
    // 初始化实例管理器
    this.configPath = path.join(__dirname, "../../../instanceConfig.json");
    this.signalTemplatePath = path.join(__dirname, "../../../signalTemplate");
    this.signalsPath = path.join(__dirname, "../../../signals");
    this.config = this.loadConfig();
  }

  // 从文件加载配置
  loadConfig() {
    try {
      const configData = fs.readFileSync(this.configPath, "utf8");
      return JSON.parse(configData);
    } catch (error) {
      throw new Error(`加载配置文件失败: ${error.message}`);
    }
  }
  // 获取所有实例列表
  async getAllInstances() {
    try {
      // 从数据库中查询所有实例
      const instances = await UEInstance.find({})
        .sort({ createdAt: -1 })
        .populate("project");

      return {
        code: 200,
        status: "success",
        message: "获取实例列表成功",
        data: instances,
      };
    } catch (error) {
      throw new Error(`获取实例列表失败: ${error.message}`);
    }
  }

  // 创建新实例
  async createInstance(instanceData) {
    try {
      // 验证必要字段
      if (!instanceData.name || !instanceData.projectId) {
        throw new Error("缺少必要的实例信息");
      }
      const newData = {
        name: instanceData.name,
        projectId: instanceData.projectId,
        gpuId: instanceData.gpuId || 0,
      };
      // ** 处理port
      // 获取可用端口列表
      const availablePorts = this.config.PortLimit.split(",").map((port) =>
        parseInt(port)
      );
      // 查询已使用的端口
      const usedInstances = await UEInstance.find({}, "port");
      const usedPorts = usedInstances.map((instance) => instance.port);

      // 找出未使用的端口
      const unusedPorts = availablePorts.filter(
        (port) => !usedPorts.includes(port)
      );
      if (unusedPorts.length === 0) {
        throw new Error("所有端口已被占用，无法创建新实例");
      }

      // 随机选择一个未使用的端口
      const randomIndex = Math.floor(Math.random() * unusedPorts.length);
      newData.port = unusedPorts[randomIndex];

      // ** 处理ipAddress
      newData.ipAddress = baseConfig.ipAddress || "127.0.0.1";
      // ** 处理HTTPS
      newData.useHTTPS = this.config.UseHTTPS || false;
      // ** 处理Relay
      newData.useRelay = this.config.UseRelay || false;
      // ** 处理分辨率
      if (instanceData?.useDefaultResolution) {
        newData.useDefaultResolution = true;
      } else {
        newData.useDefaultResolution = false;
        newData.resolutionX = instanceData.resolutionX || 1920;
        newData.resolutionY = instanceData.resolutionY || 1080;
      }
      // 创建新的实例记录
      const instance = new UEInstance(newData);

      // 保存到数据库
      const savedInstance = await instance.save();

      // 异步处理信令服务复制
      this._processSignalCopy(savedInstance).catch(async (error) => {
        console.error(
          `Signal copy failed for instance ${savedInstance._id}:`,
          error
        );
        try {
          savedInstance.signalStatus = "failed";
          savedInstance.status = "error";
          await savedInstance.save();
          socketClientManager.sendToModule("ueInstance", {
            type: "signal_copy_error",
            payload: {
              instanceId: savedInstance._id,
              name: savedInstance.name,
              message: error.message,
            },
          });
        } catch (dbError) {
          console.error(
            `Failed to update instance status to 'failed' for ${savedInstance._id} after signal copy error:`,
            dbError
          );
        }
      });

      return {
        code: 200,
        status: "success",
        message: "创建实例成功",
        data: savedInstance,
      };
    } catch (error) {
      throw new Error(`创建实例失败: ${error.message}`);
    }
  }

  // 删除实例
  async deleteInstance(instanceId) {
    try {
      // 从数据库中查找实例
      const instance = await UEInstance.findById(instanceId);

      if (!instance) {
        throw new Error("实例不存在");
      }

      // // 如果实例正在运行，先停止它
      // if (instance.status === "running") {
      //   await this.stopInstance(instanceId);
      // }

      // 更新实例状态为删除中
      instance.status = "deleting";
      await instance.save();

      // 异步处理删除操作
      this._processInstanceDeletion(instance).catch((error) => {
        console.error(`删除实例失败: ${error.message}`);
      });

      return {
        code: 200,
        status: "success",
        message: "实例删除中",
        data: instance,
      };
    } catch (error) {
      throw new Error(`删除实例失败: ${error.message}`);
    }
  }

  // 处理实例删除过程
  async _processInstanceDeletion(instance) {
    try {
      // 启动信令服务进程
      await new Promise((resolve, reject) => {
        pm2.connect((err) => {
          if (err) {
            console.warn(`PM2连接失败: ${err.message}`);
            resolve();
            return;
          }

          // 尝试删除信令服务进程
          pm2.delete(`signal_${instance._id}`, (err) => {
            if (err) {
              console.warn(`删除信令服务进程失败: ${err.message}`);
            }

            // 尝试删除UE进程
            pm2.delete(`ue_${instance._id}`, (err) => {
              if (err) {
                console.warn(`删除UE进程失败: ${err.message}`);
              }
              pm2.disconnect();
              resolve();
            });
          });
        });
      });

      // 2. 删除信号服务文件夹
      if (instance.signalPath) {
        const signalDir = path.join(this.signalsPath, instance._id.toString());
        await fs.promises.rm(signalDir, { recursive: true, force: true });
      }

      // 3. 从数据库中删除实例
      await UEInstance.findByIdAndDelete(instance._id);

      // 4. 发送删除完成通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_deleted",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: "实例及相关文件已完全删除",
        },
      });
    } catch (error) {
      // 如果启动过程失败，更新状态为错误
      instance.status = "error";
      await instance.save();
      // 发送删除失败通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_delete_failed",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: `删除实例失败: ${error.message}`,
        },
      });
      throw error;
    }
  }

  // 启动实例
  async startInstance(instanceId) {
    try {
      // 查找实例
      const instance = await UEInstance.findById(instanceId).populate(
        "project"
      );
      if (!instance) {
        throw new Error("实例不存在");
      }
      // // 检查实例状态
      if (instance.status === "running") {
        throw new Error("实例已经在运行中");
      }

      // 更新实例状态
      instance.status = "starting";
      await instance.save();

      // 异步检查进程启动状态
      this._processInstanceStart(instance).catch((error) => {
        console.error(`启动实例失败: ${error.message}`);
      });

      return {
        code: 200,
        status: "success",
        message: "实例启动中",
        data: instance,
      };
    } catch (error) {
      throw new Error(`启动实例失败: ${error.message}`);
    }
  }
  convertToCron(timeString) {
    const [hours, minutes] = timeString.split(":");
    return `${minutes} ${hours} * * *`;
  }

  async _processInstanceStart(instance) {
    try {
      // // 获取UE工程路径
      const ueProjectPath = instance.project.extractPath;
      if (!fs.existsSync(ueProjectPath)) {
        throw new Error("UE工程目录不存在");
      }
      if (instance.project.status !== "completed") {
        throw new Error("UE工程未完成部署");
      }
      // todo 检查key文件是否存在

      // // 获取信令服务路径
      const signalPath = instance.signalPath;
      if (!signalPath || !fs.existsSync(signalPath)) {
        throw new Error("信令服务目录不存在");
      }
      if (instance.signalStatus !== "success") {
        throw new Error("信令服务未完成部署");
      }
      // 检查执行文件是否存在
      const ueExePath = path.join(
        ueProjectPath,
        instance.project.executableName
      );
      const signalJsPath = path.join(signalPath, "cirrus.js");

      if (!fs.existsSync(ueExePath)) {
        throw new Error("UE可执行文件不存在");
      }
      if (!fs.existsSync(signalJsPath)) {
        throw new Error("信令服务文件不存在");
      }

      // 构建UE启动参数
      const ueArgs = [
        "-RenderOffscreen",
        "-Unattended",
        "-AudioMixer",
        `-graphicsadapter=${instance.gpuId}`,
        `-PixelStreamingURL=ws://${instance.ipAddress}:${instance.port + 100}`,
      ];
      if (!instance.useDefaultResolution) {
        ueArgs.push(
          "-ForceRes",
          `-ResX=${instance.resolutionX}`,
          `-ResY=${instance.resolutionY}`
        );
      }
      console.log("ueArgs:", ueArgs);
      let autoRestartCorn = "";
      if (this.config.isRestart) {
        autoRestartCorn = this.convertToCron(this.config.restartTime);
      }
      console.log("autoRestartCorn:", autoRestartCorn);
      // 启动信令服务进程
      await new Promise((resolve, reject) => {
        pm2.connect((err) => {
          if (err) reject(err);
          pm2.start(
            {
              name: `signal_${instance._id}`,
              script: "cirrus.js",
              cwd: signalPath,
              max_restarts: 5,
              cron_restart: autoRestartCorn,
            },
            (err) => {
              if (err) {
                pm2.disconnect();
                reject(err);
              }
              resolve();
            }
          );
        });
      });

      // 启动UE进程
      await new Promise((resolve, reject) => {
        pm2.start(
          {
            name: `ue_${instance._id}`,
            script: instance.project.executableName,
            args: ueArgs.join(" "),
            cwd: ueProjectPath,
            max_restarts: 5,
            cron_restart: autoRestartCorn,
          },
          (err) => {
            if (err) {
              pm2.disconnect();
              reject(err);
            }

            // 检查进程状态
            pm2.list((listErr, list) => {
              if (listErr) {
                pm2.disconnect();
                reject(listErr);
              }

              const ueProcess = list.find(
                (p) => p.name === `ue_${instance._id}`
              );
              const signalProcess = list.find(
                (p) => p.name === `signal_${instance._id}`
              );

              if (
                ueProcess?.pm2_env?.status === "online" &&
                signalProcess?.pm2_env?.status === "online"
              ) {
                instance.status = "running";
                instance
                  .save()
                  .then(() => {
                    socketClientManager.sendToModule("ueInstance", {
                      type: "instance_started",
                      payload: {
                        name: instance.name,
                        instanceId: instance._id,
                        message: "实例已完全启动",
                      },
                    });
                    pm2.disconnect();
                    resolve();
                  })
                  .catch((saveErr) => {
                    pm2.disconnect();
                    reject(saveErr);
                  });
              } else {
                const error = new Error("进程启动失败");
                pm2.disconnect();
                reject(error);
              }
            });
          }
        );
      });

      // 发送进程启动通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_starting",
        payload: {
          name: instance.name,
          instanceId: instance._id,
          message: "进程启动中，等待进程就绪",
        },
      });
    } catch (error) {
      // 如果启动过程失败，更新状态为错误
      instance.status = "error";
      await instance.save();

      // 发送错误通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_start_failed",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: `启动实例失败: ${error.message}`,
        },
      });

      throw error;
    }
  }
  // 停止实例
  async stopInstance(instanceId) {
    try {
      // 查找实例
      const instance = await UEInstance.findById(instanceId);
      if (!instance) {
        throw new Error("实例不存在");
      }

      // 检查实例状态
      if (instance.status !== "running") {
        throw new Error("实例未在运行中");
      }

      // 更新实例状态为停止中
      instance.status = "stopping";
      instance.clientIp = "";
      instance.isConnected = false;
      await instance.save();

      // 异步执行停止操作
      this._processInstanceStop(instance).catch((error) => {
        console.error(`停止实例失败: ${error.message}`);
      });

      return {
        code: 200,
        status: "success",
        message: "实例停止中",
        data: instance,
      };
    } catch (error) {
      throw new Error(`停止实例失败: ${error.message}`);
    }
  }

  // 处理实例停止过程
  async _processInstanceStop(instance) {
    try {
      // 停止 PM2 进程
      await new Promise((resolve, reject) => {
        pm2.connect((err) => {
          if (err) reject(err);
          // 停止 UE 进程
          pm2.delete(`ue_${instance._id}`, (err) => {
            if (err) {
              pm2.disconnect();
              reject(err);
            }
            // 停止信令服务进程
            pm2.delete(`signal_${instance._id}`, (err) => {
              if (err) {
                pm2.disconnect();
                reject(err);
              }
              pm2.disconnect();
              resolve();
            });
          });
        });
      });

      // 更新实例状态
      instance.status = "stopped";
      await instance.save();

      // 发送 WebSocket 通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_stopped",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: "实例已停止",
        },
      });
    } catch (error) {
      // 如果停止过程失败，更新状态为错误
      instance.status = "error";
      await instance.save();

      // 发送错误通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_stop_failed",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: `停止实例失败: ${error.message}`,
        },
      });

      throw error;
    }
  }

  // 获取基础配置
  async getConfig() {
    try {
      return {
        code: 200,
        status: "success",
        message: "获取配置成功",
        data: this.config,
      };
    } catch (error) {
      throw new Error(`获取配置失败: ${error.message}`);
    }
  }

  // 处理信令服务复制过程
  async _processSignalCopy(instance) {
    try {
      // 确保目标目录存在
      const signalDir = path.join(this.signalsPath, instance._id.toString());
      if (!fs.existsSync(signalDir)) {
        fs.mkdirSync(signalDir, { recursive: true });
      }

      // 复制模板文件夹内容
      await fs.promises.cp(this.signalTemplatePath, signalDir, {
        recursive: true,
      });

      // 读取并修改config.json配置
      const configPath = path.join(signalDir, "config.json");
      const configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
      if (instance.useRelay) {
        configData.peerConnectionOptions = JSON.stringify({
          offerExtmapAllowMixed: false,
          iceServers: [
            {
              urls: [this.config.stun, this.config.turn],
              username: this.config.username,
              credential: this.config.credential,
            },
          ],
        });
      }
      if (instance.useHTTPS) {
        configData.UseHTTPS = this.config.UseHTTPS;
        configData.HttpsPort = parseInt(this.config.HttpsPort);
        configData.HTTPSCertFile = this.config.HTTPSCertFile;
        configData.HTTPSKeyFile = this.config.HTTPSKeyFile;
      } else {
        configData.HttpPort = parseInt(instance.port);
      }
      configData.StreamerPort = instance.port + 100; // 假设StreamerPort是HttpPort + 100
      configData.instanceId = instance._id.toString();
      configData.platformPort = baseConfig.port;
      configData.platformHost = baseConfig.ipAddress;
      // 保存修改后的配置
      fs.writeFileSync(configPath, JSON.stringify(configData, null, 2), "utf8");

      // 更新实例信息
      instance.signalPath = signalDir;
      instance.signalStatus = "success";
      await instance.save();

      // 发送复制完成通知
      socketClientManager.sendToModule("ueInstance", {
        type: "signal_copy_completed",
        payload: {
          name: instance.name,
          instanceId: instance._id,
          signalPath: instance.signalPath,
        },
      });
    } catch (error) {
      throw error;
    }
  }

  async setConfig(newConfig) {
    try {
      // 验证新配置的结构
      if (!newConfig || typeof newConfig !== "object") {
        throw new Error("无效的配置数据");
      }

      // 更新内存中的配置
      this.config = { ...this.config, ...newConfig };

      // 将新配置写入文件
      fs.writeFileSync(
        this.configPath,
        JSON.stringify(this.config, null, 4),
        "utf8"
      );

      return {
        code: 200,
        status: "success",
        message: "更新配置成功",
        data: this.config,
      };
    } catch (error) {
      throw new Error(`更新配置失败: ${error.message}`);
    }
  }
  async msgBySignal(signalData) {
    try {
      const {
        instanceId,
        signalHost,
        signalPort,
        useHttps,
        isConnected,
        clientIp,
      } = signalData;

      // 查找实例
      const instance = await UEInstance.findById(instanceId);
      if (!instance) {
        throw new Error(`找不到实例: ${instanceId}`);
      }

      // 更新实例信息
      instance.signalHost = signalHost;
      instance.signalPort = signalPort;
      instance.useHttps = useHttps;
      instance.clientIp = clientIp;
      instance.isConnected = isConnected;
      // 保存更新后的实例
      await instance.save();

      // 发送websocket消息到前端
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_connection_message",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          signalHost,
          signalPort,
          useHttps,
          clientIp,
          status: isConnected,
          message: isConnected ? "客户端已连接" : "客户端已断开连接",
        },
      });

      return {
        code: 200,
        status: "success",
        message: "信令数据处理成功",
        data: instance,
      };
    } catch (error) {
      throw new Error(`信令数据接收失败: ${error.message}`);
    }
  }
  async clearClient(instanceId) {
    try {
      // 查找实例
      const instance = await UEInstance.findById(instanceId);
      if (!instance) {
        throw new Error(`找不到实例: ${instanceId}`);
      }

      if (!instance.signalHost || !instance.signalPort) {
        instance.clientIp = "";
        instance.isConnected = false;
        await instance.save();
        throw new Error(`实例: ${instanceId} 没有连接到信令服务`);
      }

      // 构建请求URL
      const protocol = instance.useHTTPS ? "https" : "http";
      const requestUrl = `${protocol}://${instance.signalHost}:${instance.signalPort}/clearClient`;
      // 发送GET请求
      const response = await axios.get(requestUrl);
      console.log(`clearClient请求响应: ${response}`);
      // 检查响应状态
      if (response.status === 200 && response.data.status) {
        // 更新实例状态
        instance.clientIp = "";
        instance.isConnected = false;
        await instance.save();

        // 发送WebSocket通知
        socketClientManager.sendToModule("ueInstance", {
          type: "client_cleared",
          payload: {
            instanceId: instance._id,
            name: instance.name,
            message: "客户端连接已清理",
          },
        });

        return {
          code: 200,
          status: "success",
          message: "客户端连接已清理",
          data: instance,
        };
      } else {
        throw new Error("清理客户端连接失败");
      }
    } catch (error) {
      throw new Error(`清理客户端连接失败: ${error.message}`);
    }
  }
  async restartInstance(instanceId) {
    try {
      // 查找实例
      const instance = await UEInstance.findById(instanceId);
      if (!instance) {
        throw new Error(`找不到实例: ${instanceId}`);
      }

      // 检查实例状态
      if (instance.status !== "running") {
        throw new Error("实例未在运行中，无法重启");
      }

      // 更新实例状态为重启中
      instance.status = "restarting";
      await instance.save();

      // 异步执行重启操作
      this._processInstanceRestart(instance).catch((error) => {
        console.error(`重启实例失败: ${error.message}`);
      });

      return {
        code: 200,
        status: "success",
        message: "实例重启中",
        data: instance,
      };
    } catch (error) {
      throw new Error(`重启实例失败: ${error.message}`);
    }
  }

  // 处理实例重启过程
  async _processInstanceRestart(instance) {
    try {
      // 发送重启进行中的通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_restarting",
        payload: {
          name: instance.name,
          instanceId: instance._id,
          message: "进程重启中，等待进程就绪",
        },
      });

      // 构建PM2进程配置
      let autoRestartCron = "";
      if (this.config.isRestart) {
        autoRestartCron = this.convertToCron(this.config.restartTime);
      }

      // 检查进程状态的函数
      const checkProcessStatus = async () => {
        const list = await new Promise((innerResolve, innerReject) => {
          pm2.list((listErr, list) => {
            if (listErr) {
              innerReject(listErr);
              return;
            }
            innerResolve(list);
          });
        });

        const ueProcess = list.find((p) => p.name === `ue_${instance._id}`);
        const signalProcess = list.find(
          (p) => p.name === `signal_${instance._id}`
        );

        // 如果任一进程为error状态，则失败
        if (
          ueProcess?.pm2_env?.status === "errored" ||
          signalProcess?.pm2_env?.status === "errored"
        ) {
          throw new Error("进程启动失败");
        }

        // 如果两个进程都online，则成功
        if (
          ueProcess?.pm2_env?.status === "online" &&
          signalProcess?.pm2_env?.status === "online"
        ) {
          return true;
        }

        // 其他状态继续等待
        return false;
      };

      // 重启进程
      await new Promise((resolve, reject) => {
        pm2.connect(async (err) => {
          if (err) {
            pm2.disconnect();
            reject(err);
            return;
          }

          try {
            // 重启信令服务进程
            await new Promise((innerResolve, innerReject) => {
              pm2.restart(
                `signal_${instance._id}`,
                {
                  cron_restart: autoRestartCron,
                },
                (err) => {
                  if (err) {
                    innerReject(err);
                    return;
                  }
                  innerResolve();
                }
              );
            });

            // 重启UE进程
            await new Promise((innerResolve, innerReject) => {
              pm2.restart(
                `ue_${instance._id}`,
                {
                  cron_restart: autoRestartCron,
                },
                (err) => {
                  if (err) {
                    innerReject(err);
                    return;
                  }
                  innerResolve();
                }
              );
            });

            // 开始循环检查进程状态
            let checkCount = 0;
            const maxChecks = 5;

            while (checkCount < maxChecks) {
              try {
                const isOnline = await checkProcessStatus();
                console.log(
                  `Checking process status...`,
                  instance._id,
                  isOnline
                );
                if (isOnline) {
                  // 更新实例状态
                  instance.status = "running";
                  await instance.save();

                  // 发送重启完成通知
                  socketClientManager.sendToModule("ueInstance", {
                    type: "instance_restarted",
                    payload: {
                      name: instance.name,
                      instanceId: instance._id,
                      message: "实例已重启完成",
                    },
                  });

                  pm2.disconnect();
                  resolve();
                  return;
                }

                // 等待5秒后继续检查
                await new Promise((resolve) => setTimeout(resolve, 5000));
                checkCount++;

                // 发送检查进度通知
                socketClientManager.sendToModule("ueInstance", {
                  type: "instance_restarting",
                  payload: {
                    name: instance.name,
                    instanceId: instance._id,
                    message: `进程启动中，剩余${maxChecks - checkCount}次检查`,
                  },
                });
              } catch (error) {
                pm2.disconnect();
                reject(error);
                return;
              }
            }

            // 超过最大检查次数
            pm2.disconnect();
            reject(new Error("进程启动超时，未能达到在线状态"));
          } catch (error) {
            pm2.disconnect();
            reject(error);
          }
        });
      });
    } catch (error) {
      // 如果重启过程失败，更新状态为错误
      instance.status = "error";
      await instance.save();

      // 发送错误通知
      socketClientManager.sendToModule("ueInstance", {
        type: "instance_restart_failed",
        payload: {
          instanceId: instance._id,
          name: instance.name,
          message: `重启实例失败: ${error.message}`,
        },
      });

      throw error;
    }
  }
  async getAvailableInstances() {
    try {
      const instances = await UEInstance.find({
        status: "running",
        isConnected: false,
      }).select({
        gpuId: 1,
        _id: 1,
        ipAddress: 1,
        isConnected: 1,
        name: 1,
        port: 1,
        resolutionX: 1,
        resolutionY: 1,
        status: 1,
        useDefaultResolution: 1,
        useHTTPS: 1,
        useRelay: 1,
        createdAt: 1,
      });
      
      return {
        code: 200,
        status: "success",
        message: "可用实例获取成功",
        data: instances,
      };
    } catch (error) {
      console.error("获取可用实例失败:", error);
      throw error;
    }
  }
}

// 创建单例实例
const ueInstanceManager = new UEInstanceManager();

module.exports = ueInstanceManager;
